<?php
/* Class contains logic relating to books */
class book {

	const LOCATION_ALL 		= 1;
	const LOCATION_GROUP 	= 2;
	const LOCATION_USER 	= 3;
	const LOCATION_PUBLIC 	= 4;

	const MOVE_UP 			= 1;
	const MOVE_DOWN 		= 2;
	const MOVE_RESORT 		= 1;
	const MOVE_AFTERDELETE 	= 2;
	
	const POSITION_APPEND = -100;

	public static function getUserBooks($uID, $limit = 5){
		$dbCon = db::singleton();
		$sql = "SELECT bID, name, description, private FROM " . SYS_DB_DBNAME . ".book WHERE user_uID=" . $uID . " AND group_gID IS NULL LIMIT 0, " . $dbCon->real_escape_string($limit);
		
		$result = $dbCon->single( $sql );
		return $result;
	}
	
	public static function getGroupBooks($gID, $limit = 5){
		$dbCon = db::singleton();
		$sql = "SELECT bID, name, description, private FROM " . SYS_DB_DBNAME . ".book WHERE group_gID=" . $dbCon->real_escape_string($gID) . " LIMIT 0, " . $dbCon->real_escape_string($limit);
		
		$result = $dbCon->single( $sql );
		return $result;	
	}	
	
	public static function getBookList($ID, $start, $end, $type = "user"){
		// Get books for either uID or gID. Also fetch the total amount of records.

		$dbCon = db::singleton();

		
		switch($type){
			case "user":
				$sql = "SELECT SQL_CALC_FOUND_ROWS bID, name, description, private FROM " . SYS_DB_DBNAME . ".book WHERE user_uID=" . $ID . " AND group_gID IS NULL LIMIT " . $dbCon->real_escape_string((int)$start) . "," . $dbCon->real_escape_string((int)$end);
			break;
			
			case "group":
				$sql = "SELECT SQL_CALC_FOUND_ROWS bID, name, description, private FROM " . SYS_DB_DBNAME . ".book WHERE group_gID=" . $ID . " LIMIT " . $dbCon->real_escape_string((int)$start) . "," . $dbCon->real_escape_string((int)$end);
			break;
			
			default:
				throw new PicBoardException("no book filter type selected");
			break;
		}
		
		$result = $dbCon->single( $sql );
		
		$numRows = $dbCon->oneRow( "SELECT FOUND_ROWS()" );
		
		return array_merge($result, $numRows);				
		
	}	

	public static function getBookLibrary($bID, $returnData = false){
		/*
		SELECT IF(group.gID IS NULL, 'My Charts' , group.name) AS library
		FROM picboard.chart
		LEFT JOIN picboard.group ON chart.group_gID=group.gID
		WHERE chart.chID=27;
		*/
		
		$dbCon = db::singleton();
		
		$sql = "SELECT IF(group.gID IS NULL, 'My Books' , group.name) AS library, gID, group.name FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".group ON book.group_gID=group.gID WHERE book.bID=" . $dbCon->real_escape_string((int)$bID) . ";";
		
		$result = $dbCon->oneRow( $sql );
		
		return ($returnData) ? $result : $result['library'];
	}

	
	public static function getClones(user &$userObj, $originalID, $location = book::LOCATION_ALL){
		$dbCon = db::singleton();
		
		switch($location){
			case book::LOCATION_ALL:
				$sql = "SELECT * FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".group ON book.group_gID = group.gID WHERE originator_uID=" . $userObj->getuID() . " AND clone_of=" . $dbCon->real_escape_string((int)$originalID);			
			break;
			
			case book::LOCATION_GROUP:
				$sql = "SELECT * FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".group ON book.group_gID = group.gID WHERE originator_uID=" . $userObj->getuID() . " AND clone_of=" . $dbCon->real_escape_string((int)$originalID) . " AND group_gID IS NOT NULL";
			break;
		}
		
		$result = $dbCon->single($sql);
		
		return $result;
	}
	
	public static function cloneBook(user &$userObj, $originalID, $location, $locationID, $deepClone = true){
		// Clone the book into $location, using $locationID
		
		if(is_integer($location) == false || is_integer($originalID) == false || is_integer($locationID) == false) throw new PicBoardException("Arguments must be integers.");
		
		// Does this user have access to this book?
		if(book::bookExistsAndClonable($userObj, $originalID) == false) return false;


		$dbCon = db::singleton();
		
		
		// Different save locations	
		switch($location){
		
			case book::LOCATION_USER:
				$saveLocation = chart::LOCATION_LOCAL;
				$saveID = 0;
				$sql = "INSERT INTO " . SYS_DB_DBNAME . ".book (user_uID, group_gID, originator_uID, name, description, private, clone_of) SELECT " . $dbCon->real_escape_string($userObj->getuID()) . ", NULL, originator_uID, name, description, private, '" . $dbCon->real_escape_string($originalID) . "' FROM " . SYS_DB_DBNAME . ".book WHERE bID=" . $dbCon->real_escape_string($originalID);
			break;
			
			case book::LOCATION_GROUP:
				// Does the user have access to the target location?
				
				if($userObj->isInGroup($locationID, user::GROUP_ADMINONLY) == false) throw new PicBoardException("You do not have permission to add assets to this group.");
				
				$saveLocation = chart::LOCATION_GROUP;
				$saveID = $locationID;
				$sql = "INSERT INTO " . SYS_DB_DBNAME . ".book (user_uID, group_gID, originator_uID, name, description, private, clone_of) SELECT NULL, " . $dbCon->real_escape_string((int)$locationID) . ", originator_uID, name, description, private, '" . $dbCon->real_escape_string($originalID) . "' FROM " . SYS_DB_DBNAME . ".book WHERE bID=" . $dbCon->real_escape_string($originalID);
			break;
			
			case book::LOCATION_PUBLIC:	
				// Clone a book (and all of its children) into the public library
				$saveLocation = chart::LOCATION_PUBLIC;
				$saveID = 0;
				$sql = "INSERT INTO " . SYS_DB_DBNAME . ".book (user_uID, group_gID, originator_uID, name, description, private, clone_of) SELECT NULL, NULL, originator_uID, name, description, private, '" . $dbCon->real_escape_string($originalID) . "' FROM " . SYS_DB_DBNAME . ".book WHERE bID=" . $dbCon->real_escape_string($originalID);
			break;
			
			default:
				throw new PicBoardException("location (argument 3) must be set.");
			break;
		
		}

		$dbCon->startTransaction();		

		try {
			// Clone the book
			
			$dbCon->single($sql);
			
			// Get the ID of the new book
			$newBookID = $dbCon->insert_id;
			
			// Get charts
			$charts = chart::getBookCharts($originalID, 500);			
			
			if($deepClone == true){
				// Clone all the books charts.
				
				// Clone each chart.
				foreach($charts as $chart){
					$result = chart::duplicateChart($userObj, $chart['chID'], $chart['name'], $saveLocation, $saveID);
					
					if($result['status'] == "success"){
						// Get the new chart's ID.
						$newChartID = $result['chartID'];
						book::linkChartBook($userObj, $newChartID, $newBookID);
					} else {
						return $result;
					}
				}
			
			} else {
				// Link the charts to the current new book.
				foreach($charts as $chart){
					book::linkChartBook($userObj, $chart['chID'], $newBookID);
				}
			}
						
		
			$dbCon->commit();
			return $newBookID;
		
		} catch(Exception $e){
			$dbCon->rollback();
			return false;
		}		
		
	}
	
	public static function linkChartBook(user &$userObj, $chartID, $bookID, $position = book::POSITION_APPEND){
		$dbCon = db::singleton();
		
		//echo "linkChartBook-position: $position";
		
		$dbCon->startTransaction();
		
		try {
			// Delete any existing relationships
			
			$sql = "DELETE FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string($bookID) . " AND chart_chID=" . $dbCon->real_escape_string($chartID);
			
			$dbCon->single($sql);
			
			switch($position){
			
				case book::POSITION_APPEND:
					// Get the current max position in this book.
					$position = (int) book::getBookPositionCount($userObj, $bookID);
					$position++;
				break;
				
				default:
					$position = (int) $position;	
					//echo "pos:" . $position;
					// Shift anything below down.
					// Move down all the rows below this if not book::POSITION_APPEND.
					// Get the next book so that we can move it up once this has been deleted
					$nextChartID = book::getChartAtPosition($userObj, $bookID, $position);
					//echo "nextchartid:" . $nextChartID;
					if($nextChartID != ""){
						// Move up all of the rows.
						if( book::moveChartPosition($userObj, $bookID, $nextChartID, book::MOVE_DOWN, book::MOVE_AFTERDELETE) == false ) throw new PicBoardException("Unable to move chart position");
					}
				break;
				
			}
			
			// Form the new relationship
			
			$sql = "INSERT INTO " . SYS_DB_DBNAME . ".book_chart (book_bID, chart_chID, position) VALUES(" . $dbCon->real_escape_string((int)$bookID) . "," . $dbCon->real_escape_string((int)$chartID) . ", " . $position . ")";
			
			$dbCon->single($sql);
			
			$dbCon->commit();
			return true;
		} catch(Exception $e){
			$dbCon->rollback();
			return false;
		}
		
	}
	
	public static function removeLinkChartBook(user &$userObj, $chartID, $bookID){
		
		$dbCon = db::singleton();
		
		$dbCon->startTransaction();
		
		try {
		
			$bookPosition = book::getChartPosition($userObj, $bookID, $chartID);
			
			// Get the next book so that we can move it up once this has been deleted
			$nextBookID = book::getChartAtPosition($userObj, $bookID, $bookPosition + 1);
			
			$sql = "DELETE FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string($bookID) . " AND chart_chID=" . $dbCon->real_escape_string($chartID);
			
			$dbCon->single($sql);
			
			if($nextBookID != ""){
				// Move up all of the rows.
				if( book::moveChartPosition($userObj, $bookID, $nextBookID, book::MOVE_UP, book::MOVE_AFTERDELETE) == false ) throw new PicBoardException("Unable to move chart position");
			}
			
			$dbCon->commit();
			return true;
		} catch(Exception $e){
			$dbCon->rollback();
			throw new PicBoardException($e->getMessage());
		}
	}
	
	public static function moveChartPosition(user &$userObj, $bookID, $chartID, $direction, $syncAction = book::MOVE_RESORT){
		$dbCon = db::singleton();
	
		// Get position of chart in book.
		$bookPosition = book::getChartPosition($userObj, $bookID, $chartID);
		
		switch($direction){
		
			case book::MOVE_UP:
				// New Position
				$newPosition = (int) $bookPosition - 1;
			break;
			
			case book::MOVE_DOWN:
				// New Position
				$newPosition = (int) $bookPosition + 1;
			break;
			
			default:
				throw new PicBoardException("Please enter a valid direction - either book::MOVE_UP or book::MOVE_DOWN");
			break;
		
		}

		if($newPosition < 0) throw new PicBoardException("Cannot move chart in this direction.");
		
		$dbCon->startTransaction();
		
		
		try {
		
			// Get the chart at the new position
			$chartToSwitch = book::getChartAtPosition($userObj, $bookID, $newPosition);
			

			
			if($syncAction == book::MOVE_RESORT){
			
				// Update the target
				$sql = "UPDATE " . SYS_DB_DBNAME . ".book_chart SET position=" . $dbCon->real_escape_string($newPosition) . " WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " AND chart_chID=" . $dbCon->real_escape_string((int)$chartID);
				$dbCon->single($sql);
						
				// Move the row below.
				$sql = "UPDATE " . SYS_DB_DBNAME . ".book_chart SET position=" . $dbCon->real_escape_string($bookPosition) . " WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " AND chart_chID=" . $dbCon->real_escape_string((int)$chartToSwitch);
				$dbCon->single($sql);
			}
			
			if($syncAction == book::MOVE_AFTERDELETE){
				
				// Move everything up / down depending on move direction
				if($direction == book::MOVE_UP) $operator = "-";
				if($direction == book::MOVE_DOWN) $operator = "+";
				$sql = "UPDATE " . SYS_DB_DBNAME . ".book_chart SET book_chart.position = (position " . $operator . " 1) WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " AND book_chart.position >= " . $bookPosition . ";";
				$dbCon->single($sql);
			}
			
			$dbCon->commit();
			return true;
		} catch(Exception $e){
			$dbCon->rollback();
			throw new PicBoardException($e->getMessage());
		}

	}

	public static function getChartPosition(user &$userObj, $bookID, $chartID){
		/*
			SELECT position
			FROM book_chart
			WHERE book_bID=17
			ORDER BY position DESC
			LIMIT 0, 1
		*/
		
		$dbCon = db::singleton();
		
		$sql = "SELECT position FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " AND chart_chID=" . $dbCon->real_escape_string((int)$chartID) . " ORDER BY position DESC LIMIT 0, 1";
		
		$result = $dbCon->oneRow($sql);
		
		// If there is no value set, set to 0.
		if($result['position'] == "") $result['position'] = 0;
		
		return (int) $result['position'];
	}
	
	public static function getChartAtPosition(user &$userObj, $bookID, $position){
		/*
			SELECT position
			FROM book_chart
			WHERE book_bID=17
			ORDER BY position DESC
			LIMIT 0, 1
		*/
		
		$dbCon = db::singleton();
		
		$sql = "SELECT chart_chID FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " AND position=" . $dbCon->real_escape_string((int)$position) . " LIMIT 0, 1";
		//echo $sql;
		$result = $dbCon->oneRow($sql);
		
		return (int) $result['chart_chID'];
	}
	
	public static function getBookPositionCount(user &$userObj, $bookID){
		/*
			SELECT position
			FROM book_chart
			WHERE book_bID=17
			ORDER BY position DESC
			LIMIT 0, 1		
		*/
		
		$dbCon = db::singleton();
		
		$sql = "SELECT position FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string((int)$bookID) . " ORDER BY position DESC LIMIT 0, 1";
		
		$result = $dbCon->oneRow($sql);
		
		// If there is no value set, set to 0.
		if($result['position'] == "") $result['position'] = 0;
		
		return (int) $result['position'];
	}
	
	public static function getGroupBookFromOriginalID($bookID, $group_ID){
		$dbCon = db::singleton();
	
		$sql = "SELECT bID FROM " . SYS_DB_DBNAME . ".book WHERE group_gID=" . $dbCon->real_escape_string((int)$group_ID) . " AND clone_of=" . $dbCon->real_escape_string((int)$bookID);

		$result = $dbCon->oneRow( $sql );

		return (int) $result['bID'];	
	}	
	
	public static function bookOwnerID($bookID){
		$dbCon = db::singleton();
	
		$sql = "SELECT book.user_uID, book.group_gID FROM " . SYS_DB_DBNAME . ".book WHERE bID=" . $dbCon->real_escape_string((int)$bookID);
	
		$result = $dbCon->oneRow( $sql );
		
		return $result;	
	}
	
	public static function getOriginator($bookID){
		$dbCon = db::singleton();

		$sql = "SELECT book.originator_uID, user.uID, user.userName FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".user ON book.originator_uID = user.uID WHERE bID=" . $dbCon->real_escape_string((int)$bookID);

		$result = $dbCon->oneRow( $sql );
		
		return $result;	
	}
	
	public static function getBook(user &$userObj, $bookID){
		$dbCon = db::singleton();
	
		$sql = "SELECT book.bID, book.user_uID, book.name, book.description, book.private, book.originator_uID, group_user.group_gID, group_user.isAdmin, group_user.active FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".group_user ON book.group_gID = group_user.group_gID AND group_user.user_uID=" . $userObj->getuID() . " WHERE bID=" . $dbCon->real_escape_string($bookID);
	
		$result = $dbCon->oneRow( $sql );
		
		return $result;
	
	}
	
	public static function getUserBookThumbs($uID){
		// Get thumbs for a book
		/*
		SELECT IF(mulberryURL='', imageURL, mulberryURL) AS image, book_chart.book_bID
		FROM picboard.cell
		LEFT JOIN picboard.image ON cell.image_imgID=image.imgID
		LEFT JOIN picboard.chart ON cell.chart_chID=chart.chID
		LEFT JOIN picboard.book_chart ON chart.chID=book_chart.chart_chID
		WHERE chart.user_uID=1 AND mulberryURL != "" AND book_chart.book_bID IS NOT NULL OR chart.user_uID=1 AND image.imageURL IS NOT NULL AND book_chart.book_bID IS NOT NULL
		GROUP BY chart.chID
		*/

		$dbCon = db::singleton();
	
		$sql = "SELECT IF(mulberryURL='', imageURL, mulberryURL) AS image, book_chart.book_bID FROM " . SYS_DB_DBNAME . ".cell LEFT JOIN " . SYS_DB_DBNAME . ".image ON cell.image_imgID=image.imgID LEFT JOIN " . SYS_DB_DBNAME . ".chart ON cell.chart_chID=chart.chID LEFT JOIN " . SYS_DB_DBNAME . ".book_chart ON chart.chID=book_chart.chart_chID WHERE chart.user_uID=" . $dbCon->real_escape_string($uID) . " AND mulberryURL != '' AND book_chart.book_bID IS NOT NULL OR chart.user_uID=" . $dbCon->real_escape_string($uID) . " AND image.imageURL IS NOT NULL AND book_chart.book_bID IS NOT NULL GROUP BY chart.chID";	
		
		$result = $dbCon->single( $sql );
		
		$output = array();
		
		foreach($result as $thumb){ $output[$thumb['book_bID']] = $thumb['image']; }
		
		return $output;
	
	}

	public static function getGroupBookThumbs($gID){
		// Get thumbs for a book
		/*
		SELECT IF(mulberryURL='', imageURL, mulberryURL) AS image, book_chart.book_bID
		FROM picboard.cell
		LEFT JOIN picboard.image ON cell.image_imgID=image.imgID
		LEFT JOIN picboard.chart ON cell.chart_chID=chart.chID
		LEFT JOIN picboard.book_chart ON chart.chID=book_chart.chart_chID
		WHERE chart.group_gID=1 AND mulberryURL != "" AND book_chart.book_bID IS NOT NULL OR chart.group_gID=1 AND image.imageURL IS NOT NULL AND book_chart.book_bID IS NOT NULL
		GROUP BY chart.chID
		*/

		$dbCon = db::singleton();
	
		$sql = "SELECT IF(mulberryURL='', imageURL, mulberryURL) AS image, book_chart.book_bID FROM " . SYS_DB_DBNAME . ".cell LEFT JOIN " . SYS_DB_DBNAME . ".image ON cell.image_imgID=image.imgID LEFT JOIN " . SYS_DB_DBNAME . ".chart ON cell.chart_chID=chart.chID LEFT JOIN " . SYS_DB_DBNAME . ".book_chart ON chart.chID=book_chart.chart_chID WHERE chart.group_gID=" . $dbCon->real_escape_string($gID) . " AND mulberryURL != '' AND book_chart.book_bID IS NOT NULL OR chart.group_gID=" . $dbCon->real_escape_string($gID) . " AND image.imageURL IS NOT NULL AND book_chart.book_bID IS NOT NULL GROUP BY chart.chID";	
		
		$result = $dbCon->single( $sql );
		
		$output = array();
		
		foreach($result as $thumb){ $output[$thumb['book_bID']] = $thumb['image']; }
		
		return $output;
	
	}
	
	public static function canCreateBook(user &$userObj, $book){
		/*
		SELECT COUNT(*) AS conflicts, book.group_gID, group_user.isAdmin
		FROM picboard.book
		LEFT JOIN picboard.group_user ON book.group_gID = group_user.group_gID
		WHERE book.user_uID=1 AND book.name='Test Book'
		GROUP BY book.bID
		*/
		
		// Check to see if there is a chart already with the same name etc
		$dbCon = db::singleton();

		$sql = "SELECT COUNT(*) AS conflicts, book.group_gID, group_user.isAdmin FROM " . SYS_DB_DBNAME . ".book LEFT JOIN " . SYS_DB_DBNAME . ".group_user ON book.group_gID = group_user.group_gID WHERE book.user_uID=" . $userObj->getuID() . " AND book.name='" . $dbCon->real_escape_string($book['name']) . "'";
		
		// is this a book for the user, or a group?
		if($book['type'] == 'personal'){
			$sql .=  "AND book.group_gID IS NULL GROUP BY book.bID";
		} else {
			$sql .= " AND book.group_gID IS NOT NULL GROUP BY book.bID";
		}
		
		$result = $dbCon->oneRow( $sql );
		
		if($result == null) return ($result['conflicts'] == 0) ? true : false;
		
		if($result['group_gID'] != "" && $result['isAdmin'] == 0) return false;
		
		
		return false;
	
	}
	
	public static function createBook(user &$userObj, $book){
		$dbCon = db::singleton();
		
		if($book['group_gID'] != "" || (int)$book['group_gID'] != 0) {
			if( book::userAllowedToSaveInGroup($userObj, $book['group_gID']) == false) return array("status" => "failure", "reason" => "You are not allowed to save to this group.");
		} else {
			$book['group_gID'] = "NULL";
		}
		
		$book['permissions'] = ($book['visibility'] == "bookOpen") ? 0 : 1;
		
		$sql = "INSERT INTO " . SYS_DB_DBNAME . ".book (user_uID, group_gID, originator_uID, name, description, private) VALUES (" . $userObj->getuID() . ", " . $dbCon->real_escape_string($book['group_gID']) . ", " . $userObj->getuID() . " , '" . $dbCon->real_escape_string($book['name']) . "', '" . $dbCon->real_escape_string($book['description']) . "', " . $book['permissions'] . ")";
		
		$dbCon->startTransaction();
		
		try {
			$dbCon->oneRow( $sql );
			
			$bookID = $dbCon->insert_id;
			
			$dbCon->commit();
			
			return array("status" => "success", "bookID" => $bookID);
			
		} catch (Exception $e){
			$dbCon->rollback();
			return array("status" => "failure", "reason" => "Commit error", "error_message" => $e->getMessage());
		}
		
		
	}
	
	public static function userAllowedToSaveInGroup(user &$userObj, $groupID){
		$dbCon = db::singleton();
		$sql = "SELECT COUNT(*) AS permissions FROM " . SYS_DB_DBNAME . ".group_user WHERE user_uID=" . $userObj->getuID() . " AND isAdmin=1 AND group_gID=" . $dbCon->real_escape_string($groupID) . "";
		
		$result = $dbCon->oneRow($sql);
		
		return ($result['permissions'] == 1) ? true : false;
	}
	
	public static function updateBook(user &$userObj, $book){
		if(book::bookExistsAndModifiable( $userObj, $book['bID'] ) ){
			$dbCon = db::singleton();
			
			$dbCon->startTransaction();
			try {
				// Remove current associations
				$removeSQL = "DELETE FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $book['bID'] . ";";
				$dbCon->single($removeSQL);
						
				$addSQL = "INSERT INTO " . SYS_DB_DBNAME . ".book_chart (book_bID, chart_chID) VALUES%s";
				$output = "";
			
				foreach($book['charts'] as $chart){
					$output .= sprintf("(%d, %d),", $book['bID'], $chart );
				}
				
				$addSQL = sprintf($addSQL, rtrim($output, ",") . ";");
				$dbCon->single($addSQL);

				// Update the clone_of field.

				$sql = "UPDATE " . SYS_DB_DBNAME . ".book SET clone_of=NULL WHERE bID=" . $dbCon->real_escape_string((int)$book['bID']);
				
				$dbCon->single($sql);

				// Add new associations
				$dbCon->commit();
				return true;
			} catch(Exception $e){
				$dbCon->rollback();
				return false;
			}
		} else {
			return false;
		}
	}
	
	public static function updateDetails(user &$userObj, $bookID, array $bookDetails){
		$bookID = (int) $bookID;
	
		if(book::bookExistsAndModifiable( $userObj, $bookID ) ){
			$dbCon = db::singleton();
			
			$dbCon->startTransaction();
			try {
						
				$sql = "UPDATE " . SYS_DB_DBNAME . ".book SET name='" . $dbCon->real_escape_string($bookDetails['name']) . "', description='" . $dbCon->real_escape_string($bookDetails['description']) . "' WHERE bID=" . $dbCon->real_escape_string($bookID);
				
				$dbCon->single($sql);

				// Add new associations
				$dbCon->commit();
				return true;
			} catch(Exception $e){
				$dbCon->rollback();
				return false;
			}			
		} else {
			return false;
		}
	}
	
	public static function delete(user &$userObj, $bookID, $fullDelete = false){
		$bookID = (int) $bookID;
	
		if( book::bookExistsAndModifiable( $userObj, $bookID ) ){
		
			$dbCon = db::singleton();
		
			$dbCon->startTransaction();
			
			try {
				
				if($fullDelete){
					// This should not be used unless we're 'retrieving' a book from a group
					
					// Get a list of the charts in this book
					$charts = chart::getBookCharts($bookID, 500);
					foreach($charts as $chart){
						chart::deleteChart($userObj, $chart['chID']);
					}
				}
				
				$deleteLinks = "DELETE FROM " . SYS_DB_DBNAME . ".book_chart WHERE book_bID=" . $dbCon->real_escape_string($bookID);
				
				// Delete the links between this book and any asset.
				$dbCon->single($deleteLinks);
				
				
				// Delete the book container.
				$deleteOperation = "DELETE FROM " . SYS_DB_DBNAME . ".book WHERE bID=" . $dbCon->real_escape_string($bookID);
				
				$dbCon->single($deleteOperation);
				
				$dbCon->commit();
				return true;
			} catch(Exception $e){
				$dbCon->rollback();
				return false;
			}
			
			
		} else {
			return false;
		}
	}
	
	public static function bookExistsAndModifiable(user &$userObj, $bID){
		/*
		SELECT book.user_uID, book.group_gID, group_user.isAdmin, group_user.active,
		(SELECT COUNT(*) FROM group_user WHERE group_user.user_uID=1 AND group_user.group_gID = book.group_gID) AS belongsToGroup
		FROM book
		LEFT JOIN group_user
		ON book.group_gID=group_user.group_gID AND group_user.user_uID=1
		WHERE book.bID=4;		
		*/

		$dbCon = db::singleton();
		
		$sql = "SELECT book.user_uID, book.group_gID, group_user.isAdmin, group_user.active, (SELECT COUNT(*) FROM group_user WHERE group_user.user_uID=" . $userObj->getuID() . " AND group_user.group_gID = book.group_gID) AS belongsToGroup FROM " . SYS_DB_DBNAME . ".book LEFT JOIN group_user ON book.group_gID=group_user.group_gID AND group_user.user_uID=" . $userObj->getuID() . " WHERE book.bID=" . $dbCon->real_escape_string($bID) . ";";
		$res = $dbCon->oneRow( $sql );
		
		// Check to see if this user has permission to modfiy this book
		if( $res['user_uID'] == $userObj->getuID() ) return true;
		if( $res['user_uID'] != $userObj->getuID() && $res['group_gID'] != "" ){
			if((int)$res['belongsToGroup'] == 1 && (int)$res['isAdmin'] == 1 && (int)$res['active'] == 1) return true;
		}
		
		return false;
	}
	
	public static function bookExistsAndClonable(user &$userObj, $bID){
		/*
		SELECT book.user_uID, book.group_gID, group_user.isAdmin, group_user.active,
		(SELECT COUNT(*) FROM group_user WHERE group_user.user_uID=1 AND group_user.group_gID = book.group_gID) AS belongsToGroup
		FROM book
		LEFT JOIN group_user
		ON book.group_gID=group_user.group_gID AND group_user.user_uID=1
		WHERE book.bID=4;		
		*/

		$dbCon = db::singleton();
		
		$sql = "SELECT book.user_uID, book.group_gID, group_user.isAdmin, group_user.active, (SELECT COUNT(*) FROM group_user WHERE group_user.user_uID=" . $userObj->getuID() . " AND group_user.group_gID = book.group_gID) AS belongsToGroup FROM " . SYS_DB_DBNAME . ".book LEFT JOIN group_user ON book.group_gID=group_user.group_gID AND group_user.user_uID=" . $userObj->getuID() . " WHERE book.bID=" . $dbCon->real_escape_string($bID) . ";";
		$res = $dbCon->oneRow( $sql );
		
		// Check to see if this user has permission to copy this book
		if( $res['user_uID'] == $userObj->getuID() ) return true;
		if( $res['user_uID'] != $userObj->getuID() && $res['group_gID'] != "" ){
			if((int)$res['belongsToGroup'] == 1 && (int)$res['active'] == 1) return true;
		}
		
		return false;
	}

}

?>